package generation;
import java.util.ArrayList;

import ec.util.Parameter;
import ec.vector.*;
import ec.*;
import ec.multiobjective.MultiObjectiveFitness;
import ec.simple.*;
import generation.PasswordGenerationWithMutation;

public class Transformation extends Problem implements SimpleProblemForm
{	
	//definition of the parameter that could be modify in our parameter file.
	
	//define a 'path' in our parameter file where we put all our settable parameter
	public static final String P_OURVARIABLE = "our-variables";
	public Parameter defaultBase() { return new Parameter(P_OURVARIABLE); }

	//the number of generation realise between to regeneration in our application.
	public static final String I_AUTONOMEGENERATION = "autonome-generation";
	//the keyword give by the user
	public static final String P_KEYWORD = "key-word";
	//the maxSize give byt the user
	public static final String I_MAXSIZE = "max-size";	
	
	//end of the parameter

	private static int numberOfAutonomeGeneration;
	private static String keyWord;
	private static int maxSize;
	
	private ArrayList<String> evaluatedIndivString = new ArrayList<String>();
	public static boolean first = true;

	public static int getNumberOfAutonomeGeneration(){
		return numberOfAutonomeGeneration;
	}
	public static int getMaxSize(){
		return maxSize;
	}
	public static String getKeyWord(){
		return keyWord;
	}

	//set the parameter of the EA.
	public void setup(final EvolutionState state, final Parameter base)
	{
		super.setup(state,base);   // always call super.setup(...) first if it exists!
		Parameter def = defaultBase();

		numberOfAutonomeGeneration = state.parameters.getInt(base.push(I_AUTONOMEGENERATION), def.push(I_AUTONOMEGENERATION),1);
		keyWord = state.parameters.getStringWithDefault(base.push(P_KEYWORD), def.push(P_KEYWORD), "myKeyWord");
		maxSize = state.parameters.getInt(base.push(I_MAXSIZE), def.push(I_MAXSIZE), keyWord.length());	
	} 
	
	// return an arrayList of string that is the mutation of all the Indivudal contains in indivList 
	private ArrayList<String> mutatedKeyWord(ArrayList<Individual> indivList) {
		ArrayList<String> returnedList = new ArrayList<String> ();
		for(int i = 0; i < indivList.size(); i++) {
			Mutation mut = new Mutation(keyWord, maxSize-keyWord.length());
			returnedList.add(mut.applyMutation(indivList.get(i).genotypeToStringForHumans()));
		}
		return returnedList;
	}
	
	public void evaluate(EvolutionState state, Individual ind, int subpopulation, int threadnum) {
		if (ind == null || ind.evaluated)
			return;
		
		//if it's the first individual in the run that is evaluated
		if(first) {
			first = false;
			//we store the mutation of the evaluated individual in the evaluatedIndivString list.
			evaluatedIndivString = mutatedKeyWord(PasswordGenerationWithMutation.evaluatedIndiv);
		}

		//realise the mutation of the keyword for the given individual to be evaluated
		Mutation mutation = new Mutation(keyWord, maxSize-keyWord.length());
		IntegerVectorIndividual intVectorIndividual = (IntegerVectorIndividual) ind;
		String passwordString = mutation.applyMutation(intVectorIndividual.genotypeToStringForHumans());
		char[] password = passwordString.toCharArray();
		float[] objectives = ((MultiObjectiveFitness)(intVectorIndividual.fitness)).getObjectives();
		//get its strength score
		int nScore = PasswordStrength.getPasswordStrength(password);
		//normalize this score between 0 and 1
		float normalizeFitness = (float)(1 - 1/(double)(1+nScore/2));
		//put it in the multi objective
		objectives[0] = normalizeFitness;

		//calculate the memorizeScore of the individual, if there is a list of evaluatedIndividual
		float userMemorizeScore = 0;
		if(!evaluatedIndivString.isEmpty()) {
			userMemorizeScore = PasswordMemorisation.passwordMemorisation(passwordString, evaluatedIndivString);
		}
		//put the memorize score in the objective
		objectives[1] = userMemorizeScore;

		//set the objectives of the individual.
		((MultiObjectiveFitness)intVectorIndividual.fitness).setObjectives(state, objectives);
		ind.evaluated = true;

		intVectorIndividual.evaluated = true;
	}
}